package no.sachmuld.methodcombination.impl;

import no.sachmuld.methodcombination.api.MethodInvocation;

import java.lang.reflect.Method;
import java.util.Iterator;

/**
 *
 */
public abstract class AbstractMethodInvocation<B, R> implements MethodInvocation<R> {

    private Iterator<? extends B> iterator;
    private Object targetObject;
    private Method method;
    private Object[] arguments;

    protected AbstractMethodInvocation(Iterable<? extends B> iterable, Object targetObject, Method method, Object[] arguments) {
        this.iterator = iterable.iterator();
        this.targetObject = targetObject;
        this.method = method;
        this.arguments = arguments;
    }

    final public R execute() {
        return proceed();
    }

    @Override
    final public R proceed() {
        if (iterator.hasNext()) {
            B behaviour = iterator.next();
            return executeBehaviour(behaviour);
        }
        return atEnd();
    }

    @Override
    final public Object getThis() {
        return targetObject;
    }

    @Override
    final public Method getMethod() {
        return method;
    }

    @Override
    final public Object[] getArguments() {
        return arguments;
    }

    protected R atEnd() {
        return null;
    }

    protected abstract R executeBehaviour(B behaviour);
}
